package org.six11.ss.server;

import java.util.*;

import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.six11.util.Debug;
import org.six11.util.adt.MultiState;

/**
 * 
 * 
 * @author Gabe Johnson <johnsogg@cmu.edu>
 */
public class DisconnectionReaper {

  public static final long REAP_TIME = 5000;
  public static final long TIMEOUT = 30L * 1000L;
  
  protected final static SessionFactory sessionFactory;
  static {
    sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
  }

  private MultiState state;

  /**
   * @param state
   */
  public DisconnectionReaper(MultiState state) {
    this.state = state;
  }

  /**
   * Called once, which initiates a periodic task that calls the reap() method.
   */
  public void go() {
    Timer timer = (Timer) state.getValue(ServerStateNames.TASK_TIMER);
    TimerTask task = new TimerTask() {
      public void run() {
        reap();
      }
    };
    timer.schedule(task, REAP_TIME, REAP_TIME);
    log("Started session reaper");
  }

  private static void log(String what) {
    Debug.out(">>  DisconnectionReaper", what);
  }

  @SuppressWarnings("unchecked")
  public void reap() {
    Map<String, Long> lastSeen = (Map<String, Long>) state
        .getValue(ServerStateNames.SESSION_LAST_SEEN);
    long now = System.currentTimeMillis();
    long then, elapsed;
    Collection<String> doomed = new ArrayList<String>();
    for (String k : lastSeen.keySet()) {
      then = lastSeen.get(k);
      elapsed = now - then;
      if (elapsed > TIMEOUT) {
        doomed.add(k);
      }
    }
    if (doomed.size() > 0) {
      log("reaping " + doomed.size() + " slackers!");
      LogoutHandler lh = getLogoutHandler();
      getHibernate().setFlushMode(FlushMode.ALWAYS);
      Transaction tx = getHibernate().beginTransaction();
      try {
        for (String victim : doomed) {
          lh.logout(victim);
        }
      } finally {
        tx.commit();
      }

    }
  }

  protected Session getHibernate() {
    return sessionFactory.getCurrentSession();
  }

  private LogoutHandler getLogoutHandler() {
    Map<String, AppletMessageHandler> handlers = (Map<String, AppletMessageHandler>) state
        .getValue(ServerStateNames.HANDLERS);
    return (LogoutHandler) handlers.get("logout");
  }

}
